package com.code.soulnetty.modbus.client.message;

import com.code.soulnetty.modbus.biz.Utils;
import com.code.soulnetty.modbus.biz.msg.Message;
import com.google.common.collect.ImmutableSortedSet;
import lombok.ToString;
import org.apache.commons.lang3.tuple.Pair;

/**
 * modbus 读取消息
 *
 **/
@ToString
public abstract class ModbusReadRequest implements ProtocolRequest {
    final ImmutableSortedSet<Message> requestList;
    final byte[] data;

    short msgId;
    boolean autoMsg;

    protected ModbusReadRequest(ImmutableSortedSet<Message> requestList, int byteLen) {
        this(requestList, byteLen, false);
    }

    protected ModbusReadRequest(ImmutableSortedSet<Message> requestList, int byteLen, short msgId) {
        this.requestList = requestList;
        this.data = new byte[byteLen];
        this.msgId = msgId;
        initData();
    }

    protected ModbusReadRequest(ImmutableSortedSet<Message> requestList, int byteLen, boolean autoMsg) {
        this.requestList = requestList;
        this.data = new byte[byteLen];
        this.autoMsg = autoMsg;
        initData();
    }

    void initData() {
        int index = handleAduHeader();
        handlePdu(index);
        handleAduTail(index + 5);
    }

    /**
     * 处理ADU头部
     *
     * @return 头部长度
     */
    abstract int handleAduHeader();

    /**
     * 处理ADU尾部
     *
     * @param index
     */
    abstract void handleAduTail(int index);

    /**
     * 处理pdu部分
     *
     * @param index
     */
    private void handlePdu(int index) {
        //添加头
        final Message first = requestList.first();
        final Message last = requestList.last();
        //fc
        final byte fc = first.getFc();
        //寄存器/线圈开始位置
        final int start = first.getOffset();
        final int end = last.getOffset();
        //最后一个地址减去开始的地址加上最后一个数据占用的寄存器数量
        final int length = end - start + last.getDataType().getRegisterCount();
        data[index] = fc;
        setShort(data, ++index, (short) start);
        setShort(data, index + 2, (short) length);
    }

    @Override
    public byte[] requestByteData() {
        return data;
    }

    @Override
    public Pair<Boolean, String> msgIdInfo() {
        final Message first = requestList.first();
        final String msgKey = String.valueOf(first.getChannelId());
        if (autoMsg) {
            final short autoMsgId = Utils.nextShort(msgKey);
            setShort(data, 0, autoMsgId);
            return Pair.of(Boolean.TRUE, autoMsgId + "_" + first.getFc());
        }
        return Pair.of(Boolean.FALSE, msgId + "_" + first.getFc());
    }


    @Override
    public ImmutableSortedSet<Message> requestData() {
        return requestList;
    }

    void setShort(byte[] memory, int index, short value) {
        memory[index] = (byte) (value >> 8);
        memory[index + 1] = (byte) value;
    }
}
